package com.wkbb.common.utils;

import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * @author jt
 */

@Slf4j
public class DateUtil {
    public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_MIN_PATTERN = "yyyyMMddHHmm";
    public static final String DATE_PATTERN = "yyyy-MM-dd";
    public static final String TIME_PATTERN = "HH:mm:ss";
    public static final String TIME_MIN_PATTERN = "HH:mm";
    public static final String DATE_MONTH_DAY_PATTERN = "MM月dd日";

    private static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
    private static DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(DATE_PATTERN);
    private static DateTimeFormatter timeMinFormat = DateTimeFormatter.ofPattern(TIME_MIN_PATTERN);
    private static DateTimeFormatter dateMonthDayPattern = DateTimeFormatter.ofPattern(DATE_MONTH_DAY_PATTERN);
    private static DateTimeFormatter dateMinPattern = DateTimeFormatter.ofPattern(DATE_MIN_PATTERN);

    private static SimpleDateFormat yyyyMMddFormatter = new SimpleDateFormat("yyyyMMdd");
    public static SimpleDateFormat dateSDF = new SimpleDateFormat(DATE_PATTERN);
    public static SimpleDateFormat dateMinSDF = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    public static SimpleDateFormat chDateSDF = new SimpleDateFormat("yyyy年MM月dd日");


    /**
     * yyyyMMdd 格式时间
     *
     * @return
     */
    public static String getTodayyyyyMMdd() {
        Date date = new Date();
        return yyyyMMddFormatter.format(date);
    }
    /**
     * yyyyMMdd 格式时间
     *
     * @return
     */
    public static String getTodayyyyMMddHHmm() {
        Date date = new Date();
        return dateMinPattern.format(toZonedDateTime(date));
    }


    public static String toString(LocalDateTime localDateTime) {
        return dateTimeFormatter.format(localDateTime);
    }
    public static String toYmdString(Date localDateTime) {
        return dateSDF.format(localDateTime);
    }

    public static String toChYmdString(Date localDateTime) {
        return chDateSDF.format(localDateTime);
    }

    public static String toMinString(Date date) {
        LocalDateTime localDateTime = toLocalDateTime(date);
        return timeMinFormat.format(localDateTime);
    }

    public static String toDayMinString(Date date) {
        LocalDateTime localDateTime = toLocalDateTime(date);
        return dateMinPattern.format(localDateTime);
    }

    public static String toMonthDayString(LocalDate localDate) {
        return dateMonthDayPattern.format(localDate);
    }

    public static LocalDateTime toLocalDateTime(String s) {
        return LocalDateTime.parse(s, dateTimeFormatter);
    }

    public static LocalDate toLocalDate(String s) {
        return LocalDate.parse(s, dateFormatter);
    }

    public static ZonedDateTime toZonedDateTime(Date date) {
        return ZonedDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
    }

    public static LocalDateTime toLocalDateTime(Date date) {
        return toZonedDateTime(date).toLocalDateTime();
    }

    public static LocalDate toLocalDate(Date date) {
        return toLocalDateTime(date).toLocalDate();
    }

    public static Date toDate(LocalDate localDate) {
        return toDate(localDate.atStartOfDay());
    }

    private static Date toDate(LocalDateTime localDateTime) {
        return toDate(localDateTime.atZone(ZoneId.systemDefault()));
    }

    private static Date toDate(ZonedDateTime zonedDateTime) {
        return Date.from(zonedDateTime.toInstant());
    }

    public static Stream<LocalDate> range(LocalDate startInclusive, LocalDate endExclusive) {
        Iterator<LocalDate> iterator = new Iterator<LocalDate>() {
            LocalDate current = null;
            LocalDate next = startInclusive;

            @Override
            public boolean hasNext() {
                return next.isBefore(endExclusive);
            }

            @Override
            public LocalDate next() {
                current = next;
                next = next.plusDays(1);
                return current;
            }
        };
        Iterable<LocalDate> iterable = () -> iterator;
        return StreamSupport.stream(iterable.spliterator(), false);
    }

    public static Stream<LocalDate> rangeClosed(LocalDate startInclusive, LocalDate endInclusive) {
        return range(startInclusive, endInclusive.plusDays(1));
    }

    /**
     * 获取月份所有天和星期集合
     * @param yearMonth 月份
     * @return 天和星期集合
     */
    public static List<Map<String,Object>> getMonthDaysList(YearMonth yearMonth){
        LocalDate start = toLocalDate(yearMonth.toString()+"-01");
        LocalDate end = start.with(TemporalAdjusters.lastDayOfMonth());
        List<Map<String,Object>> monthList = new ArrayList<>();
        DateUtil.rangeClosed(start, end).forEach(e -> monthList.add(MapUtil.newParamMap(
                "day", DateUtil.toMonthDayString(e),
                "week", TimeUtil.dateToWeek(e.toString())
        )));
        return monthList;
    }

    /**
     * 获取两个时间间隔分钟
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 间隔分钟
     */
    public static int getDateTimeBetweenMin(LocalTime startTime, LocalTime endTime){
        return (int)(Duration.between(startTime, endTime).getSeconds() / 60);
    }

    /**
     * 获取两个时间间隔分钟
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 间隔分钟
     */
    public static int getDateTimeBetweenMin(LocalDateTime startTime, LocalDateTime endTime){
        return (int)(Duration.between(startTime, endTime).getSeconds() / 60);
    }

    //将星期转换为对应的系数  1－6代表周一到周六。0代表周日
    public static Integer getWeekNum(String strWeek) {
        Integer number = 1;//默认为星期日
        if ("周日".equals(strWeek)) {
            number = 0;
        } else if ("周一".equals(strWeek)) {
            number = 1;
        } else if ("周二".equals(strWeek)) {
            number = 2;
        } else if ("周三".equals(strWeek)) {
            number = 3;
        } else if ("周四".equals(strWeek)) {
            number = 4;
        } else if ("周五".equals(strWeek)) {
            number = 5;
        } else if ("周六".equals(strWeek)) {
            number = 6;
        }
        return number;
    }


    //返回当前日期加X天后的日期
    public static String addCurrDay(int i) {
        try {
            Calendar gCal = Calendar.getInstance();
            gCal.add(GregorianCalendar.DATE, i);
            return dateMinSDF.format(gCal.getTime());
        } catch (Exception e) {
            return getDate();
        }
    }
    public static String getDate() {
        try {
            return dateMinSDF.format(Calendar.getInstance().getTime());
        } catch (Exception e) {
            log.debug("DateUtil.getDate():" + e.getMessage());
            return "";
        }
    }


    public static List<String> getDayOfWeekWithinDateInterva2(String dataBegin, String dataEnd, int weekNum, List<Integer> weekDays) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        if (dataEnd == null){
//            dataEnd  = dateMinSDF.format(addCurrDay(700));
            Calendar gCal = Calendar.getInstance();
            gCal.add(GregorianCalendar.DATE, 700);
            dataEnd = dateMinSDF.format(gCal.getTime());
        }else{
            dataEnd  = dataEnd + " 23:59";
        }
        List<String> dateResult = new ArrayList<>();
        Calendar cal = Calendar.getInstance();
        String[] dateInterval = {dataBegin, dataEnd};
        Date[] dates = new Date[dateInterval.length];
        for (int i = 0; i < dateInterval.length; i++) {
            String[] ymd = dateInterval[i].split("[^\\d]+");
            cal.set(Integer.parseInt(ymd[0]), Integer.parseInt(ymd[1]) - 1, Integer.parseInt(ymd[2]));
            dates[i] = cal.getTime();
        }
        for (Date date = dates[0]; date.compareTo(dates[1]) <= 0; ) {
            cal.setTime(date);
            for (Integer weekDay:weekDays) {
                if (cal.get(Calendar.DAY_OF_WEEK) -1 == weekDay) {
                    String format = sdf.format(date);
                    //是否是休息日
                    dateResult.add(format);
                }
            }
            cal.add(Calendar.DATE, 1);
            date = cal.getTime();
            if (dateResult.size() == weekNum){
                return dateResult;
            }
        }
        return dateResult;
    }

    public static void main(String[] args) {
//        Calendar gCal = Calendar.getInstance();
//        gCal.add(GregorianCalendar.DATE, 700);
//        System.out.println(dateMinSDF.format(gCal.getTime()));

        try {
            Date startTime = dateMinSDF.parse("2023-3-22 20:00");
            Date endTime = dateMinSDF.parse("2023-4-20 20:00");
            System.out.println(startTime.toString());
            System.out.printf(endTime.toString());
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

    }

}
